#include "datacontainer.h"
#include "datasuite.h"


#include <QMetaProperty>
#include <QDebug>


DataContainer::DataContainer(DataSuite *parent) :
    AbstractModelItem(parent),
    d(new Data())
{
}

DataContainer::DataContainer(const DataContainer &other) :
    AbstractModelItem(other.parent()),
    d(other.d)
{
}

int DataContainer::fieldCount() const
{
    if (!metaData())
    {
        return internalFieldCount();
    }

    return internalFieldCount() + metaData()->itemNames().count();
}


QVariant DataContainer::value(int field, int role) const
{
    if (role != Qt::DisplayRole && role != Qt::EditRole)
    {
        return QVariant();
    }


    if (field < internalFieldCount())
    {
        return metaPropertyValue(field);
    }


//    switch (field)
//    {
//    case Field_NAME:
//        return name();

//    default:
//        break;
//    }

    return property(fieldName(field).toByteArray());
}


bool DataContainer::setValue(int field, const QVariant &value, int role)
{
    if (role != Qt::EditRole)
    {
        return false;
    }

    if (field < internalFieldCount())
    {
        return setMetaPropertyValue(field, value);
    }

    QByteArray propertyName = fieldName(field).toByteArray();
    if (propertyName.isEmpty())
    {
        return false;
    }

    return setProperty(propertyName, value);
}

QVariant DataContainer::fieldName(int field) const
{
    if (field < internalFieldCount())
    {
        if (type() == QMetaType::type("Skill"))
        {
            qDebug() << Q_FUNC_INFO << internalFieldCount();
        }
        return metaPropertyName(field);
    }


    int index = (field - internalFieldCount());

    if (!metaData())
    {
        qDebug() << Q_FUNC_INFO << "Invalid meta data!" << name();
        return QVariant();
    }

    QString metaItemName = metaData()->itemName(index);
    if (metaItemName.isEmpty())
    {
//        qDebug() << Q_FUNC_INFO << "Empty meta item name!" << name() << field << internalFieldCount();
        return QVariant();
    }

    return metaItemName;
}

bool DataContainer::setFieldName(int field, const QString &name)
{
    if (field < internalFieldCount())
    {
        return false;
    }

    int index = field - internalFieldCount();

    MetaData* meta = metaData();
    if (!meta)
    {
        qDebug() << Q_FUNC_INFO << "Meta data is invalid!" << d->name;
        return false;
    }

    meta->setItemName(index, name);
    return true;
}

void DataContainer::addField(const QString &name)
{
    MetaData* meta = metaData();
    if (!meta)
    {
        qDebug() << Q_FUNC_INFO << "Invalid meta data!" << d->name;
        return;
    }

    meta->addItem(name);
    emit sigChanged();
}

QString DataContainer::name() const
{
    return d->name;
}

void DataContainer::setName(const QString &name)
{
    if (name == d->name) return;
    d->name = name;
    emit sigChanged();
}

QList<DataContainer *> DataContainer::childData() const
{
    QList<DataContainer*> ret;
    foreach (QObject* child, children())
    {
        DataContainer* data = qobject_cast<DataContainer*>(child);
        if (!data)
        {
            continue;
        }

        ret.append(data);
    }

    return ret;
}

QString DataContainer::objectPath() const
{
    if (name().isEmpty())
    {
        return QString();
    }

    DataContainer* parentData = qobject_cast<DataContainer*>(parent());
    if (!parentData)
    {
        return name();
    }

    QString parentPath = parentData->objectPath();
    if (parentPath.isEmpty())
    {
        return name();
    }

    return QString("%1.%2").arg(parentPath).arg(name());
}


MetaData *DataContainer::metaData() const
{
    DataSuite* suite = qobject_cast<DataSuite*>(parent());

    if (!suite) return 0;

    return suite->containerMetaData();
}

int DataContainer::internalFieldCount() const
{
    int ret = metaObject()->propertyCount()-1; // strip objectName property.
//    if (ret > 1)
//    {
//        qDebug() << Q_FUNC_INFO << name() << ret;
//    }
    return ret;
}

QString DataContainer::metaPropertyName(int field) const
{
    int index = field+1;
    if (index >= metaObject()->propertyCount())
    {
        return QString();
    }

    return metaObject()->property(index).name();
}

QVariant DataContainer::metaPropertyValue(int field) const
{
//    qDebug() << Q_FUNC_INFO << field;

    int index = field+1;
    if (index >= metaObject()->propertyCount())
    {
        qDebug() << Q_FUNC_INFO << metaObject()->className() << field;
        return QVariant();
    }

    return metaObject()->property(index).read(this);
}

bool DataContainer::setMetaPropertyValue(int field, const QVariant &value)
{
    int index = field+1;
    if (index >= metaObject()->propertyCount())
    {
        return false;
    }

    return metaObject()->property(index).write(this, value);
}

